/***************************************************************************
 *   Copyright (C) 2007-2010 by Lasse Liehu                                *
 *   lliehu@kolumbus.fi                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "google_reader_notifier_qt.h"
#include "config.h"

// C++ standard library
#include <cassert>

// State & settings classes
#include "googlelogindata.h"
#include "notifiersettings.h"
#include "notifierworkingstate.h"

// Operation classes (login & checking)
#include "qtloginoperation.h"
#ifdef Q_WS_WIN
#include "integration/win32loginoperation.h"
#endif
#include "unreaditemscheck.h"

// GUI classes
#include "aboutbox.h"
#include "logwidget.h"
#include "settingsform.h"
#include "unreadcountwindow.h"
#include "failedauthenticationdialog.h"

// Qt core
#include <QMap>
#include <QTimer>
#include <QSettings>
#include <QtDebug>

// Qt GUI
#include <QFont>
#include <QAction>
#include <QMenu>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QMessageBox>
#include <QErrorMessage>

//BEGIN GoogleReaderNotifierQtPrivate
class GoogleReaderNotifierQtPrivate
{
    public:
        GoogleReaderNotifierQtPrivate(QSystemTrayIcon& systemTray)
        : workingState(systemTray)
        {
        }

        QSystemTrayIcon *systemTray;
        LogWidget *log;

        NotifierSettings settings;

        QTimer startOfCheckTimer; // timers the sarting times of a check
        UnreadItemsCheck *checkObj; // if this is NOT null then a check oper is ongoing
        LoginOperation *loginObj; // if this is NOT null then a login oper is ongoing
        // if this is NOT a null-ptr, then when the login obj in it finishes,
        // a check should be done
        LoginOperation *doCheckWhenLoginFinishes;

        UnreadCountWindow *unreadCountWin;
        QErrorMessage *unreadCountWindowCloseMsg;
        SettingsForm *settingsForm;

        NotifierWorkingState workingState;

        Login::Conclusion lastLoginConclusion;
        QString lastLoginConclusionDetails;
        bool showFailedAuthDlg;
        QMap<QString, int> unreadCountCache;
};
//END GoogleReaderNotifierQtPrivate

google_reader_notifier_qt::google_reader_notifier_qt(QSystemTrayIcon *systemTray)
    : d(new GoogleReaderNotifierQtPrivate(*systemTray))
{
    d->systemTray = systemTray;
    d->checkObj = 0;
    d->loginObj = 0;
    d->doCheckWhenLoginFinishes = 0;
    d->unreadCountWin = 0;
    d->unreadCountWindowCloseMsg = new QErrorMessage;
    d->settingsForm = 0;
    d->lastLoginConclusion = Login::UnknownError;
    d->showFailedAuthDlg = true;

    d->log = new LogWidget;
    connect(this, SIGNAL(refreshingOfSettingsNeeded() ), d->log,
        SLOT(readGeneralSettings() ));
    connect(this, SIGNAL(refreshingOfSettingsNeeded() ), d->log,
        SLOT(readWindowSettings() ));

    connect(&d->settings, SIGNAL(checkingIntervalChanged()), this,
            SLOT(slotCheckingIntervalChanged() ));
    connect(&d->settings, SIGNAL(isUnreadCountShownInWindowChanged()), this,
            SLOT(slotIsUnreadCountShownInWindowChanged() ));

    d->settings.readSettings();
    d->settings.loginData().connectDefaultPasswordAsker();

    setupSystemTray(systemTray);

    QSettings settings;
    bool hasFirstrunAlreadyBeenRun =
        settings.value("has_firstrun_already_been_run", false).toBool();
    SettingsForm *settingsForm = 0;
    if (!hasFirstrunAlreadyBeenRun)
    {
        QMessageBox::information(0 /*parent*/, tr("Welcome to Google Reader Notifier Qt!"),
                                 tr("<strong>Welcome to Google Reader Notifier Qt!</strong>"
                                 "<br>Please enter your Google account information.<br>It is "
                                 "needed for the application to function properly."));
#ifdef Q_WS_WIN
        if (QMessageBox::question(0 /*parent*/, tr("Google Reader Notifier Qt"),
            tr("Would you like Google Reader Notifier Qt to\nautomatically "
            "start when you log in?\nYou can turn this off later if you like to."),
            QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
        {
            d->settings.setAutostartEnabled(true);
            d->settings.writeSettings();
        }
#endif
        settingsForm = slotShowSettings();
        settingsForm->setAttribute(Qt::WA_DeleteOnClose);
        settings.setValue("has_firstrun_already_been_run", true);
        // These connections will only cause the slot to be called once because
        // after that the SettingsForm is destroyed
        connect(settingsForm, SIGNAL(ready()), this,
            SLOT(slotStartChecking() ));
        connect(settingsForm, SIGNAL(ready()), &d->startOfCheckTimer, SLOT(start()));
    }
    else
    {
        d->startOfCheckTimer.start();
        slotStartChecking();
    }

    connect(&d->startOfCheckTimer, SIGNAL(timeout()), this, SLOT(slotStartChecking() ));

    // Connect d->workingState signals
    connect(&d->workingState, SIGNAL(stateWasSet(bool)), this, SLOT(updateSystemTray() ));
    connect(&d->workingState, SIGNAL(stateWasSet(bool)), this,
        SLOT(clearUnreadCountCache(bool) ));
    connect(this, SIGNAL(refreshingOfSettingsNeeded() ), &d->settings,
        SLOT(readSettings() ));

    if (d->settings.isUnreadCountShownInWindow() ) slotShowUnreadCountWin();
}

google_reader_notifier_qt::~google_reader_notifier_qt()
{
    delete d->unreadCountWindowCloseMsg;
    delete d->log;
    if (d->unreadCountWin) d->unreadCountWin->close();
    if (d->settingsForm) d->settingsForm->close();
    delete d;
}

const QMap<QString, int>& google_reader_notifier_qt::unreadCountCache() const
{
    return d->unreadCountCache;
}

GoogleLoginData& google_reader_notifier_qt::loginData()
{
    return d->settings.loginData();
}

NotifierSettings& google_reader_notifier_qt::settings()
{
    return d->settings;
}

NotifierWorkingState& google_reader_notifier_qt::workingState()
{
    return d->workingState;
}

/**
 * This member function fits the given text in the given width (which is in
 * pixels) @c intoWidth when the given font @c usingFont is used to
 * paint/render/whatever the text.
 *
 * @note This member function modifies the font size of the given parameter
 *     @c usingFont.
 */
void google_reader_notifier_qt::fitTextIntoWidth(const QString& text,
    int intoWidth, QFont &usingFont)
{
    QFont font(usingFont);
    qreal ptSize = font.pointSizeF();
    QFontMetrics fm(font);
    int w = fm.width(text);
    if (w > intoWidth)
    {
        ptSize *= qreal(intoWidth) / qreal(w);
        font.setPointSizeF(ptSize);
    }
}

void google_reader_notifier_qt::about() const
{
    AboutBox box;
    box.exec();
}

SettingsForm *google_reader_notifier_qt::slotShowSettings()
{
    // if a settings dialog is already open
    if (d->settingsForm)
    {
        d->settingsForm->show();
        d->settingsForm->raise();
        return d->settingsForm;
    }

    // if it's not then open it and such

    d->settingsForm = new SettingsForm(*this, *d->log, d->settings);
    connect(d->settingsForm, SIGNAL(refreshingOfSettingsNeeded()), this,
        SIGNAL(refreshingOfSettingsNeeded() ));
    connect(&d->settings, SIGNAL(settingsRead()), d->settingsForm,
        SLOT(readSettings() ) );
    connect(d->settingsForm, SIGNAL(destroyed()), this,
        SLOT(slotMarkSettingsFormDeleted() ));
    d->settingsForm->show();
    return d->settingsForm;
}

void google_reader_notifier_qt::slotShowLog()
{
    d->log->show();
    d->log->raise();
}

void google_reader_notifier_qt::updateSystemTray()
{
    if (d->workingState.isUpAndWorking() )
    {
        if (unreadCountCache().isEmpty() )
        {
            d->systemTray->setToolTip(tr("No unread items"));
            d->systemTray->setIcon(QIcon(":/grnotifqt.svg"));
        }
        else
        {
            QString msg;
            msg += tr("Total %n unread item(s)\n\n", "",
                      unreadCountCache().value("system/total", 0));
            msg += tr("Tags:\n");
            QMapIterator<QString, int> iter(unreadCountCache());
            while (iter.hasNext() )
            {
                iter.next();
                if ( ! iter.key().contains("label/") ) continue;
                msg += tr("%1: %n unread item(s)\n", "", iter.value() ).
                       arg(iter.key().mid(6) /*tag name*/);
            }
            d->systemTray->setToolTip(msg);
            d->systemTray->setIcon(QIcon(":/grnotifqt_newitems.svg"));
        }
    }
    else
    {
        d->systemTray->setIcon(QIcon(":/grnotifqt_error.svg"));

        QString toolTip = tr("STATUS: Not working.\n");
        if (d->workingState.reasonForNotWorking() == NotifierWorkingState::CheckFailed)
        {
            toolTip += tr("REASON: Checking of unread items' count failed.");
        }
        else if (d->workingState.reasonForNotWorking() == NotifierWorkingState::LoginFailed)
        {
            toolTip += tr("REASON: Login failed.");
        }
        else
        {
            toolTip += tr("REASON: Unknown.");
        }
        if (d->workingState.isReasonForNotWorkingDateTimeSet() )
        {
            if (d->workingState.reasonForNotWorkingDateTime().date() == QDate::currentDate() )
            {
                toolTip += tr("\nSINCE: %1").arg(d->workingState.reasonForNotWorkingDateTime().
                           time().toString(Qt::TextDate) );
            }
            else
            {
                toolTip += tr("\nSINCE: %1").arg(d->workingState.reasonForNotWorkingDateTime().
                           toString(Qt::TextDate) );
            }
        }
        if ( ! d->workingState.reasonForNotWorkingExtraInfo().isEmpty() )
        {
            toolTip += tr("\nINFO: %1").arg(d->workingState.reasonForNotWorkingExtraInfo() );
        }
        d->systemTray->setToolTip(toolTip);
    }
}

void google_reader_notifier_qt::slotStartLogin()
{
    if (!d->loginObj)
    {
        d->log->writeToLog(tr("login"), tr("Login operation started."));
#if defined(Q_WS_WIN) && defined(USE_WIN32LOGINCODE_ON_WIN)
        d->loginObj = new Win32LoginOperation(d->settings.loginData() );
#else
        d->loginObj = new QtLoginOperation(d->settings.loginData() );
#endif
        connect(d->loginObj, SIGNAL(updateStatus(Login::Status)), this,
                SLOT(slotLoginUpdateStatus(Login::Status) ));
        connect(d->loginObj, SIGNAL(setConclusion(Login::Conclusion,QString)),
                this, SLOT(slotLoginSetConclusion(Login::Conclusion, QString) ));
        d->loginObj->start();
    }
    else
    {
        d->log->writeToLog(tr("login"), tr("Login operation was not started because it was "
            "already ongoing."), LogWidget::Debug);
    }
}

void google_reader_notifier_qt::updateUnreadCountCache(const QMap<QString, int>& counts)
{
    // Set wasNoUnreadBefore and unreadCountGrew variables
    bool wasNoUnreadBefore = false;
    bool unreadCountGrew = false;
    if (unreadCountCache().isEmpty() ) wasNoUnreadBefore = true;
    else
    {
        int oldCount = unreadCountCache().value("system/total", 0);
        int newCount = counts.value("system/total", 0);
        if (newCount > oldCount) unreadCountGrew = true;
    }
    if (wasNoUnreadBefore && !counts.isEmpty() )
        unreadCountGrew = true;

    // Update the cache and the status of other parts accordingly
    d->unreadCountCache = counts;
    if (d->unreadCountWin)
    {
        d->unreadCountWin->updateUnreadCount(QString::number(
                d->unreadCountCache.value("system/total", 0) ));
    }
    updateSystemTray();

    // Notify about new unread items, if the user wants it
    NewUnreadItemsNotificationTime notifTime = settings().notificationTime();
    if ( (notifTime == NUINT_Always && unreadCountGrew) ||
         (notifTime == NUINT_Smart && wasNoUnreadBefore && unreadCountGrew) )
    {
        d->systemTray->showMessage(tr("New unread items"),
                                  tr("You have %n unread item(s).", "",
                                  unreadCountCache().value("system/total") ));
    }
}

void google_reader_notifier_qt::resetUnreadCountWinPos()
{
    QDesktopWidget desktop;
    QRect rect = desktop.availableGeometry();
    QPoint pos;
    pos.setY(rect.top() + rect.height()/2);
    pos.setX(rect.left() + rect.width()/2);
    if (d->unreadCountWin)
    {
        d->unreadCountWin->move(pos);
    }
    else
    {
        QSettings settings("Lasse Liehu", "Google Reader Notifier Qt");
        settings.setValue("unreadcountwindow_pos", pos);
    }
}

void google_reader_notifier_qt::openReaderInBrowser() const
{
    QDesktopServices::openUrl(QUrl("http://www.google.com/reader/"));
}

void google_reader_notifier_qt::showUnreadCountWindowCloseMsg()
{
    if (d->unreadCountWindowCloseMsg)
    {
        d->unreadCountWindowCloseMsg->showMessage(tr("If you'd like to close this "
                "widget permanently, please go into the settings. This will "
                "be closed only for this session for now."));
    }
}

void google_reader_notifier_qt::slotStartChecking()
{
    if (!d->checkObj)
    {
        if (d->settings.loginData().sid().isEmpty() )
        {
            d->log->writeToLog(tr("manager"), tr("No valid login session; starting "
                "login and delaying checking to after we have that."));
            slotStartLogin();
            d->doCheckWhenLoginFinishes = d->loginObj;
            return;
        }
        d->log->writeToLog(tr("manager"), tr("Starting an unread count check."));
        d->checkObj = new UnreadItemsCheck(d->settings.loginData() );
        connect(d->checkObj, SIGNAL(checkCompleted(bool, const QString&)), this,
            SLOT(slotCheckCompleted(bool, const QString&) ));
        connect(d->checkObj, SIGNAL(unreadItemsCountUpdated(const QMap<QString, int>&)),
            this, SLOT(updateUnreadCountCache(const QMap<QString, int>&) ));
        d->checkObj->start();
    }
    else
    {
        d->log->writeToLog(tr("manager"), tr("Unread count check not started "
            "because one is ongoing."));
    }
}

void google_reader_notifier_qt::slotLoginUpdateStatus(Login::Status status)
{
    if (status != Login::Completed)
    {
        d->lastLoginConclusion = Login::UnknownError;
        d->lastLoginConclusionDetails = "";
    }

    QString logMsg = tr("[No text was set. This is a bug.]");
    switch (status)
    {
        case Login::Completed:

            if (d->lastLoginConclusion != Login::Success)
            {
                if ( ! d->settings.loginData().sid().isEmpty() )
                {
                    qDebug() << "Even though login failed, SID isn't empty, "
                                "although it should be.";
                }
                workingState().setIsUpAndWorking(false);
            }
            switch (d->lastLoginConclusion)
            {
                case Login::Success:
                    logMsg = tr("Login was completed successfully.");
                    assert(d->loginObj);
                    if (d->doCheckWhenLoginFinishes == d->loginObj && d->loginObj)
                    {
                        qDebug() << "Starting delayed (no valid SID) check";
                        QTimer::singleShot(0, this, SLOT(slotStartChecking()));
                    }
                    // NOTE There is no need to change working state, as it
                    // will be set accordingly when the next checking operation
                    // either succeeds or fails.
                    break;
                case Login::InternalError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Internal error"));
                    logMsg = tr("Login failed because of an internal error.");
                    break;
                case Login::UnknownError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Unknown error"));
                    logMsg = tr("Login failed because of an unknown error.");
                    break;
                case Login::ConnectionError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Connection error"));
                    logMsg = tr("Login failed because of a connection error.");
                    break;
                case Login::UnknownServerError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Unknown server error"));
                    logMsg = tr("Login failed because of an unknown server error.");
                    break;
                case Login::NoSidInDataError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Got unexpected login data, contact author if "
                            "problem persists"));
                    logMsg = tr("Login failed because incomprehensible login "
                             "data was got.");
                    break;
                case Login::AuthenticationError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Wrong email or password"));
                    logMsg = tr("Login failed because of a wrong email or "
                             "password.");
                    if (d->showFailedAuthDlg)
                    {
                        FailedAuthenticationDialog *dialog =
                                new FailedAuthenticationDialog(
                                d->settings.loginData() );
                        connect(dialog, SIGNAL(newLoginTryWanted()), this,
                                SLOT(slotTryNewLogin() ));
                        connect(dialog, SIGNAL(wantedToNotAskAgain()), this,
                                SLOT(slotDoNotShowFailedAuthDlg() ));
                        d->startOfCheckTimer.stop();
                        dialog->show();
                    }
                    break;
                case Login::SthNeedsFixingError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed,
                            tr("Something should be fixed in this app, contact "
                            "author"));
                    logMsg = tr("Login failed and perhaps something should be "
                                "fixed in this application. Please contact author "
                                "if the problem persists.");
                    break;
                case Login::SslError:
                    workingState().setReasonForNotWorking(
                            NotifierWorkingState::LoginFailed, tr("SSL error"));
                    logMsg = tr("An SSL error occurred when trying to establish "
                             "a secure connection to Google.");
                default:
                    logMsg = tr("We got into default block in this login "
                             "conclusion switch.");
            }

            if (d->lastLoginConclusionDetails.isEmpty() )
                d->log->writeToLog(tr("login"), logMsg, LogWidget::Normal);
            else
            {
                d->log->writeToLog(tr("login"), logMsg + tr(" More info: %1").
                                 arg(d->lastLoginConclusionDetails),
                                 LogWidget::Normal);
            }

            d->loginObj->deleteLater();
            if (d->doCheckWhenLoginFinishes == d->loginObj)
            {
                d->doCheckWhenLoginFinishes = 0;
            }
            d->loginObj = 0;
            break;

        case Login::Initializing:
            d->log->writeToLog(tr("login"), tr("Login is initializing..."),
                             LogWidget::Debug);
            break;
        case Login::RequestSent:
            d->log->writeToLog(tr("login"), tr("Login request was sent."),
                             LogWidget::Debug);
            break;
        case Login::ResponseHeaderReceived:
            d->log->writeToLog(tr("login"), tr("Response header was received."),
                             LogWidget::Debug);
            break;
        case Login::ReceivingResponseData:
            d->log->writeToLog(tr("login"), tr("Receiving login data..."),
                             LogWidget::Debug);
            break;
        case Login::ResponseDataReceived:
            d->log->writeToLog(tr("login"), tr("Received login data."), LogWidget::Debug);
            break;
        case Login::ParsingData:
            d->log->writeToLog(tr("login"), tr("Parsing login data..."), LogWidget::Debug);
            break;
        default:
            d->log->writeToLog("login/google_reader_notifier_qt::"
                             "slotLoginUpdateStatus", tr("We got into default "
                             "block in the switch statement!"), LogWidget::Debug);
    }
}

void google_reader_notifier_qt::slotLoginSetConclusion(
        Login::Conclusion conclusion, const QString& details)
{
    d->lastLoginConclusion = conclusion;
    d->lastLoginConclusionDetails = details;
}

void google_reader_notifier_qt::slotTryNewLogin()
{
    d->showFailedAuthDlg = true;
    slotStartLogin();
    // so that an unread count check will be done after login finishes
    d->doCheckWhenLoginFinishes = d->loginObj;
    d->startOfCheckTimer.start();
}

void google_reader_notifier_qt::slotDoNotShowFailedAuthDlg()
{
    d->showFailedAuthDlg = false;
    connect(&d->settings.loginData(), SIGNAL(passwordChanged(const QString&)),
            this, SLOT(setCanShowFailedAuthDlg() ));
    connect(&d->settings.loginData(), SIGNAL(emailChanged(const QString&)),
            this, SLOT(setCanShowFailedAuthDlg() ));
    d->startOfCheckTimer.start();
}

void google_reader_notifier_qt::setCanShowFailedAuthDlg()
{
    d->showFailedAuthDlg = true;
    disconnect(this, SLOT(setCanShowFailedAuthDlg() ));
}

void google_reader_notifier_qt::slotMarkSettingsFormDeleted()
{
    d->settingsForm = 0;
}

void google_reader_notifier_qt::clearUnreadCountCache(bool newState)
{
    if (!newState)
    {
        d->unreadCountCache.clear();
        //: This symbol is shown in the unread count widget if there are no unread items.
        if (d->unreadCountWin) d->unreadCountWin->updateUnreadCount(tr("X"));
    }
}

void google_reader_notifier_qt::slotShowUnreadCountWin()
{
    if (d->unreadCountWin) return;
    d->unreadCountWin = new UnreadCountWindow(":/greader_notifier_widgetbg.svg", *this);
    d->unreadCountWin->setAttribute(Qt::WA_DeleteOnClose);
    connect(d->unreadCountWin, SIGNAL(destroyed()), this,
        SLOT(slotMarkUnreadCountWinDeleted() ));
    connect(this, SIGNAL(refreshingOfSettingsNeeded()), d->unreadCountWin,
        SLOT(slotReadPosAndSize() ));
    connect(&d->settings, SIGNAL(unreadCountDisplayFontChanged()),
            d->unreadCountWin, SLOT(update() ));
    d->unreadCountWin->show();
    if (d->workingState.isUpAndWorking() )
    {
        d->unreadCountWin->updateUnreadCount(QString::number(
            d->unreadCountCache.value("system/total", 0) ));
    }
    //: This symbol is shown in the unread count widget if there are no unread items.
    else d->unreadCountWin->updateUnreadCount(tr("X"));
}

void google_reader_notifier_qt::slotMarkUnreadCountWinDeleted()
{
    d->unreadCountWin = 0;
}

void google_reader_notifier_qt::slotSysTrayActivated(
    QSystemTrayIcon::ActivationReason reason) const
{
    if (reason == QSystemTrayIcon::DoubleClick)
    {
        openReaderInBrowser();
    }
}

void google_reader_notifier_qt::slotCheckingIntervalChanged()
{
    // d->settings.checkingInterval() is in minutes and setInterval takes msecs
    d->startOfCheckTimer.setInterval(d->settings.checkingInterval()*60000 );
    if (d->startOfCheckTimer.isActive() )
    {
        d->startOfCheckTimer.start();
    }
}

void google_reader_notifier_qt::slotIsUnreadCountShownInWindowChanged()
{
    if (d->settings.isUnreadCountShownInWindow() ) slotShowUnreadCountWin();
    else if (d->unreadCountWin) d->unreadCountWin->close();
}

void google_reader_notifier_qt::slotCheckCompleted(bool succeeded, const QString& msg)
{
    if (succeeded)
    {
        if (msg.isEmpty() )
        {
            d->log->writeToLog(tr("manager"), tr("Unread count check succeeded."));
        }
        else
        {
            d->log->writeToLog(tr("manager"), tr("Unread count check succeeded "
                "with message: %1").arg(msg));
        }
    }
    else
    {
        if (msg.isEmpty() )
        {
            d->log->writeToLog(tr("manager"), tr("Unread count check failed."));
        }
        else
        {
            d->log->writeToLog(tr("manager"), tr("Unread count check failed "
                "with message: %1").arg(msg));
        }
    }
    d->workingState.setIsUpAndWorking(succeeded);
    d->workingState.setReasonForNotWorking(NotifierWorkingState::CheckFailed, msg);

    d->checkObj->deleteLater();
    d->checkObj = 0;
}

void google_reader_notifier_qt::setupSystemTray(QSystemTrayIcon *sysTray)
{
    if (!sysTray) return;

    // Creating a context menu for the system tray

    QMenu *sysTrayMenu = new QMenu;
    QAction *openReaderAct = sysTrayMenu->addAction(sysTray->tr("Open Reader"));
    QFont openReaderActFont = openReaderAct->font();
    openReaderActFont.setBold(true);
    openReaderAct->setFont(openReaderActFont);
    connect(openReaderAct, SIGNAL(triggered(bool)), this, SLOT(openReaderInBrowser() ));
    QAction *checkNowAct = sysTrayMenu->addAction(sysTray->tr("Check Now"));
    connect(checkNowAct, SIGNAL(triggered(bool)), this, SLOT(slotStartChecking() ));
    sysTrayMenu->addSeparator();
    QAction *showLogAct = sysTrayMenu->addAction(d->systemTray->tr("Show Log..."));
    connect(showLogAct, SIGNAL(triggered(bool)), this, SLOT(slotShowLog()));
    QAction *settingsAct = sysTrayMenu->addAction(sysTray->tr("Settings..."));
    connect(settingsAct, SIGNAL(triggered(bool)), this, SLOT(slotShowSettings()) );
    sysTrayMenu->addSeparator();
    QAction *aboutAct = sysTrayMenu->addAction(d->systemTray->tr("&About"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()) );
    QAction *aboutQtAct = sysTrayMenu->addAction(d->systemTray->tr("About &Qt"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()) );
    QAction *quitAct = sysTrayMenu->addAction(sysTray->tr("Quit"));
    connect(quitAct, SIGNAL(triggered(bool)), qApp, SLOT(quit()));

    sysTray->setContextMenu(sysTrayMenu);
    connect(sysTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
        this, SLOT(slotSysTrayActivated(QSystemTrayIcon::ActivationReason) ));

     // NOTE Should these really be done here?
    updateSystemTray();
    sysTray->show();
}
